var Modello = {
	version : '0.0.3',
	date : '2006-03-27'
}

var Class = new (function() {

	this.create = function() {
		var cls = function() {
			this.__class__ = arguments.callee;
			_construct.apply(this, arguments);
		}
		_extends(cls, arguments);
		cls.register = function(path, override) {
			return Class.register(this, path, override);
		}
		cls.create = _createInstance;
		cls.toString = _toStringClass;
		cls.subclassOf = function(cls) {
			return _subclassOf(this, cls);
		}
		cls.superclassOf = function(cls) {
			return _subclassOf(cls, this);
		}
		return cls;
	}

	this.register = function(cls, path, override) {
		var override = override || false;
		if (typeof cls != 'function') {
			throw new Error('Class register error: The first argument must be a function');
		}
		var pair = [];
		if (!_parse_path(path, pair)) {
			throw new Error('Class register error: Invalid class path');
		}
		var pkg = pair[0];
		var cn = pair[1];
		var old_class = _class_depository[pkg][cn];
		if (old_class) {
			if (override) {
				delete old_class.__package__;
				delete old_class.__classname__;
			} else {
				throw new Error('Class register error: Class "' + path
						+ '" already exists');
			}
		}
		_class_depository[pkg][cn] = cls;
		cls.__package__ = pkg;
		cls.__classname__ = cn;
		return cls;
	}

	this.get = function(path) {
		var pair = [];
		if (!_parse_path(path, pair, true)
				|| !_class_depository[pair[0]][pair[1]]) {
			throw new Error('Class get error: Class "' + path
					+ '" is not found');
		}
		return _class_depository[pair[0]][pair[1]];
	}

	this.abstractMethod = function() {
		throw new Error('Class runtime error: call an abstract method that has not been implemented');
	}

	this.toString = function() {
		return '[object Class]';
	}

	var _class_depository = {};

	var _parse_path = function(path, pair, check) {
		if (typeof path != 'string' || path.length == 0) {
			return false;
		}
		var arr = path.split('.');
		if (arr.length > 1) {
			pair[0] = arr.slice(0, arr.length - 1).join('.');
			pair[1] = arr[arr.length - 1];
		} else {
			pair[0] = '';
			pair[1] = path;
		}
		if (typeof _class_depository[pair[0]] != 'object') {
			if (check) {
				return false;
			} else {
				_class_depository[pair[0]] = {};
			}
		}
		return true;
	}

	var _createInstance = function() {
		var args = [];
		for (var i = 0; i < arguments.length; i++) {
			args.push('arguments[' + i + ']');
		}
		return eval('new this(' + args.join(', ') + ');');
	}

	var _extends = function(cls, args) {
		cls.__superclasses__ = [];
		for (var i = 0; i < args.length; i++) {
			var superclass = args[i];
			if (typeof superclass == 'string') {
				superclass = Class.get(superclass);
			}
			if (typeof superclass != 'function') {
				throw new Error('Class create error: Invalid superclass: '
						+ 'args[' + i + ']');
			}
			cls.__superclasses__.push(superclass);
		}
	}

	var _construct = function() {
		var cls = this.__class__;
		for (var i = cls.__superclasses__.length - 1; i >= 0; i--) {
			var s = cls.__superclasses__[i];
			eval('this.super' + i + ' = new s(Class);');
			eval('_extend(this, this.super' + i + ');');
		}
		this.__class__ = cls;
		this.toString = _toStringInstance;
		if (typeof cls.construct == 'function') {
			cls.construct.apply(this, [this, cls]);
		}
		this.getClass = function() {
			return this.__class__;
		}
		this.isA = function(cls) {
			return _subclassOf(this.__class__, cls);
		}
		this.instanceOf = _instanceOf;
		if (arguments[0] != Class && typeof this.initialize == 'function') {
			this.initialize.apply(this, arguments);
		}
	}

	var _extend = function(dest, src) {
		for (prop in src) {
			if (prop.substr(0, 5) == 'super'
					&& !isNaN(parseInt(prop.substr(5)))) {
				continue;
			}
			dest[prop] = src[prop];
		}
	}

	var _toStringClass = function() {
		if (this.__classname__) {
			if (this.__package__.length > 0) {
				return '[class ' + this.__package__ + '.' + this.__classname__
						+ ']';
			} else {
				return '[class ' + this.__classname__ + ']';
			}
		} else {
			return '[class Anonymous]';
		}
	}

	var _toStringInstance = function() {
		if (this.__class__.__classname__) {
			if (this.__class__.__package__.length > 0) {
				return '[object ' + this.__class__.__package__ + '.'
						+ this.__class__.__classname__ + ']';
			} else {
				return '[object ' + this.__class__.__classname__ + ']';
			}
		} else {
			if (this.__class__) {
				return '[object Anonymous class]';
			} else {
				return '[object Object]';
			}
		}
	}

	var _instanceOf = function(cls) {
		if (typeof cls == 'string') {
			cls = Class.get(cls);
		}
		if (typeof cls != 'function') {
			return false;
		}
		return this.__class__ == cls;
	}

	var _subclassOf = function(cls1, cls2) {
		if (typeof cls1 == 'string') {
			cls1 = Class.get(cls1);
		}
		if (typeof cls2 == 'string') {
			cls2 = Class.get(cls2);
		}
		if (typeof cls1 != 'function' || typeof cls2 != 'function') {
			return false;
		}
		if (!cls1.__superclasses__
				|| cls1.__superclasses__.constructor != Array) {
			return false;
		}
		for (var i = 0; i < cls1.__superclasses__.length; i++) {
			if (cls1.__superclasses__[i] == cls2) {
				return true;
			} else {
				if (_subclassOf(cls1.__superclasses__[i], cls2)) {
					return true;
				}
			}
		}
		return false;
	}

});

/*
 * ---------------------------- Utility methods. ----------------------------
 */
var Define = (function() {
	var __defined_macros__ = [];
	return (function(name, value) {
		if (arguments.length < 2 || typeof name != 'string') {
			throw new Error('Define error: Usage: Define(\'name\', value);');
		}
		for (var i = 0; i < __defined_macros__.length; i++) {
			if (__defined_macros__[i] == name) {
				return;
			}
		}
		if (typeof value == 'string') {
			eval('window.' + name + ' = "' + value + '";');
		} else {
			if (typeof value == 'number' || typeof value == 'boolean') {
				eval('window.' + name + ' = ' + value + ';');
			} else {
				eval('window.' + name + ' = value ;');
			}
		}
		__defined_macros__.push(name);
	});
})();

/*
 * ---------------------------- Methods for compatible.
 * ----------------------------
 */
if (!Array.prototype.push) {
	Array.prototype.push = function() {
		var l = this.length;
		for (var i = 0; i < arguments.length; i++) {
			this[l + i] = arguments[i];
		}
		return this.length;
	}
}

if (!Function.prototype.apply) {
	Function.prototype.apply = function(obj, args) {
		var arr = [];
		var obj = obj || window;
		var args = args || [];
		for (var i = 0; i < args.length; i++) {
			arr[i] = 'args[' + i + ']';
		}
		obj.__tmp_method__ = this;
		var result = eval('obj.__tmp_method__(' + arr.join(', ') + ')');
		delete obj.__tmp_method__;
		return result;
	}
}